package com.zkh.myutils.database.conutils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.zkh.myutils.database.DatabaseException;
import com.zkh.myutils.database.dbpool.ConnectConfigure;
import com.zkh.myutils.database.dbpool.DataBaseInfo;

/**
 * JDBC连接数据库，或者开启事务。与连接池没有关系。
 * @author zkh
 */
public class JDBCUtils {
	//线程局部连接
	private static ThreadLocal<Connection> threadlocal = new ThreadLocal<Connection>();
	//默认配置
	private static Map<String, DataBaseInfo> databaseInfoMap = new ConcurrentHashMap<>();
	//驱动加载情况
	private static Map<String, Boolean> typeLoaded = new ConcurrentHashMap<>();
	//默认数据源
	private static String defaultSource = ConnectConfigure.getDefualtSource();
	
	/**
	 * 数据指定数据源配置信息
	 * @param datasourceKey 数据源唯一标识
	 * @return
	 */
	private static DataBaseInfo getDataBaseInfo(String datasourceKey) {
		//获取数据源
		DataBaseInfo info = databaseInfoMap.get(datasourceKey);
		//不存在，则加载
		if(info==null) {
			//保存数据源
			databaseInfoMap.put(datasourceKey, info = ConnectConfigure.getSourceConfigById(datasourceKey));
			//未加载驱动
			if(!typeLoaded.getOrDefault(info.getDbtype().getDbType(), false)) {
				//加载驱动
				try {
					Class.forName(info.getDriver());
					//保存状态
					typeLoaded.put(info.getDbtype().getDbType(), true);
				} catch (ClassNotFoundException e) {
					throw new DatabaseException("数据库驱动加载失败，请检查驱动包是否正确，或检查驱动配置是否正确！", e);
				}
			}
		}
		//返回
		return info;
	}
	
	/**
	 * 获取默认数据源的连接对象
	 * @return 连接对象 
	 */
	public static Connection getConnection(){
		return getConnection(defaultSource);
	}
	
	/**
	 * 获取指定数据源的连接对象
	 * @param datasourceKey 数据源Key
	 * @return 连接对象 
	 */
	public static Connection getConnection(String datasourceKey) {
		//获取数据源信息
		DataBaseInfo info = getDataBaseInfo(datasourceKey);
		try {
			return DriverManager.getConnection(info.getUrl(), info.getUsername(), info.getPassword());
		} catch (SQLException e) {
			throw new DatabaseException(e);
		}
	}
	
	/**
	 * 开启事务，使用默认数据源。<br />
	 * <b>注：提交事务和回滚事务会自动关闭连接，无需手动调用close()方法</b>
	 */
	public static void beginTransaction() {
		beginTransaction(defaultSource);
	}
	
	/**
	 * 开启事务，使用指定数据源。<br />
	 * <b>注：提交事务和回滚事务会自动关闭连接，无需手动调用close()方法</b>
	 */
	public static void beginTransaction(String datasourceKey){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			transactionConnection = getConnection(datasourceKey);
		}else{
			throw new DatabaseException("系统已开启事务，请提交上次事务后再开启新事务");
		}
		//关闭自动提交
		try {
			transactionConnection.setAutoCommit(false);
			//保存事务连接
			threadlocal.set(transactionConnection);
		} catch (SQLException e) {
			throw new DatabaseException(e);
		}
	}
	
	/**
	 * 提交事务
	 */
	public static void commit(){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			throw new DatabaseException("未开启事务，提交失败");
		}else{
			//还原事务连接
			PoolUtils.restoreTransactionConnection(transactionConnection, conn->{
				try {
					//提交事务
					conn.commit();
					//删除事务连接
					threadlocal.remove();
				} catch (SQLException e) {
					throw new DatabaseException(e);
				}
			});
		}
	}
	
	/**
	 * 回滚事务
	 */
	public static void rollback(){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			throw new DatabaseException("未开启事务，回滚失败");
		}else{
			//还原事务连接
			PoolUtils.restoreTransactionConnection(transactionConnection, conn->{
				try {
					//回滚事务
					conn.rollback();
					//删除事务连接
					threadlocal.remove();
				} catch (SQLException e) {
					throw new DatabaseException(e);
				}
			});
		}
	}
}
